/**
 * 
 */
package neptune.web.server;

import it.robertobifulco.ias.IAS;
import it.robertobifulco.ias.OperationRepository;
import it.robertobifulco.ias.RepositoryException;
import it.robertobifulco.ias.principalmanager.PrincipalRepository;
import it.robertobifulco.ias.rolemanager.RoleRepository;
import java.io.File;
import neptune.manager.NeptuneManager;
import neptune.manager.allocator.MainAllocator;
import neptune.manager.builder.IPAddressRange;
import neptune.manager.configurator.SSHConfigurator;
import neptune.manager.model.topology.IPAddress;
import neptune.manager.storage.ExperimentsRepository;
import neptune.manager.storage.TopologyStorageFactory;
import neptune.manager.storage.VmTemplateRepository;
import neptune.manager.storage.XMLApplicationPropertiesStorageFactory;
import neptune.manager.storage.XMLClusterStorageFactory;
import neptune.manager.storage.XMLExperimentsRepository;
import neptune.manager.storage.XMLTemplateStorageFactory;
import neptune.manager.storage.XMLTopologyStorageFactory;
import neptune.manager.storage.XMLVmTemplateRepository;
import neptune.manager.utils.DebugLog;
import neptune.web.client.model.DefaultRoles;
import neptune.web.server.model.ApplicationUser;
import neptune.web.server.repository.ApplicationRepository;
import neptune.web.server.repository.ConfigurationRepository;
import neptune.web.server.repository.XMLConfigurationRepository;
import neptune.web.server.repository.XMLOperationsRepository;
import neptune.web.server.repository.XMLRoleRepository;
import neptune.web.server.repository.XMLUsersRepository;
import neptune.web.server.security.IASCreationException;
import neptune.web.server.security.IASHandler;

/**
 * @author Roberto Bifulco [info@robertobifulco.it, robertobifulco.it]
 * @author Luigi Lorenzo Arpino [luigiarpino@yahoo.it]
 */
public class ApplicationManager {

	private static ApplicationManager manager;
	private static String configFilePath;


	public static ApplicationManager getApplicationManager()
			throws InitializationException {
		if (manager == null) {
			manager = new ApplicationManager();
		}
		return manager;
	}
	public static void setConfigFilePath(String configFilePath) 
	{
		ApplicationManager.configFilePath = configFilePath;
	}
	public static String getConfigFilePath()
	{
		return ApplicationManager.configFilePath;
	}
	private NeptuneManager expManager;
	private ConfigurationRepository configRepository;
	private ApplicationRepository applicationRepository;
	private PrincipalRepository principalRepository;

	private RoleRepository roleRepository;
	private OperationRepository opRepository;

	private IAS ias;

	private TopologyStorageFactory topologyStorageFactory;

	private ApplicationManager() throws InitializationException {
		boolean firstRun = false;
		try {
			configRepository = new XMLConfigurationRepository(
					ApplicationManager.configFilePath);
		} catch (RepositoryException e3) {
			throw new InitializationException(e3);
		}

		Debug.setDebug(configRepository.debugActive());
		DebugLog.debug = configRepository.debugActive();

		XMLUsersRepository xmlUsersRepo = new XMLUsersRepository(new File(
				configRepository.getApplicationRootDirectoryPath()
						+ "users.xml"));

		applicationRepository = xmlUsersRepo;

		try {
			if (applicationRepository.getUsersNumber() == 0)
				firstRun = true;
		} catch (RepositoryException e2) {
			Debug.printTrace(e2);
			throw new InitializationException(e2);
		}

		principalRepository = xmlUsersRepo;
		try {
			roleRepository = new XMLRoleRepository(configRepository
					.getApplicationRootDirectoryPath()
					+ "roles.xml");
		} catch (RepositoryException e1) {
			Debug.printTrace(e1);
			throw new InitializationException(e1);
		}
		opRepository = new XMLOperationsRepository(configRepository
				.getApplicationRootDirectoryPath()
				+ "operations.xml");

		if (firstRun) { // Crea l'utente di default se e' il primo avvio
			ApplicationUser user = new ApplicationUser(false,
					DefaultRoles.SYSTEM_ADMIN, "admin");
			user.setEmail("not@defin.ed");
			user.setPassword("admin");
			try {
				applicationRepository.addUser(user);
			} catch (RepositoryException e) {
				Debug.printTrace(e);
				throw new InitializationException(e);
			}
		}

		ExperimentsRepository expRepo = new XMLExperimentsRepository(
				configRepository.getExperimentsDirPath());

		topologyStorageFactory = new XMLTopologyStorageFactory(configRepository
				.getTopologyRootDirectoryPath());

		File expDir = new File(configRepository.getExperimentsDirPath());
		expDir.mkdirs();
		File topolDir = new File(configRepository
				.getTopologyRootDirectoryPath());
		topolDir.mkdirs();

		// TODO trovare un modo di definire a runtime allocator e configurator.

		IPAddressRange controlRange = configRepository.getControlIPRange();
		IPAddress baseExperimentSubnet = configRepository
				.getBaseExperimentSubnet();
		IPAddress clusterSubnet = configRepository.getClusterSubnet();
		String linkSubnet = configRepository.getLinkSubnet();

		VmTemplateRepository vmTemplateRepository = new XMLVmTemplateRepository(
				configRepository.getVmTempRepDir());

		expManager = new NeptuneManager(expRepo, topologyStorageFactory,
					new XMLClusterStorageFactory(configRepository.getClusterFilePath()),
					new XMLTemplateStorageFactory(configRepository.getTemplatePath() ),
					new XMLApplicationPropertiesStorageFactory(configRepository.getConfigurationFilePath()),
					new MainAllocator(configRepository.getApplicationRootDirectoryPath(),
					configRepository.getVmTempRepDir(),
					configRepository.getExperimentsVMsDir()),
					new SSHConfigurator(controlRange),
					controlRange,
					baseExperimentSubnet,
					clusterSubnet,
					linkSubnet,
					vmTemplateRepository);
	}

	/**
	 * @return the applicationRepository
	 */
	public ApplicationRepository getApplicationRepository() {
		return applicationRepository;
	}

	public ConfigurationRepository getConfigRepository() {
		return configRepository;
	}

	public IAS getIAS() throws IASCreationException {
		if (ias == null)
			ias = IASHandler.getIAS(principalRepository, roleRepository,
					opRepository);
		return ias;
	}

	public NeptuneManager getNeptuneManager() {
		return expManager;
	}

	/**
	 * @return the principalRepository
	 */
	public PrincipalRepository getPrincipalRepository() {
		return principalRepository;
	}

	/**
	 * @return the roleRepository
	 */
	public RoleRepository getRoleRepository() {
		return roleRepository;
	}

	/**
	 * @return the topologyStorageFactory
	 */
	public TopologyStorageFactory getTopologyStorageFactory() {
		return topologyStorageFactory;
	}
}
